using System;
using Tarkin.InfrastructureLibrary.Core.PrimitiveTypes;

namespace Tarkin.InfrastructureLibrary.Core.Basic
{
    /// <summary>
    /// The MultiplicityElement class is the implementation of the MultiplicityElement abstract class as defined by 
    /// section 10.2.2 of the Unified Modeling Language: Infrastructure specfication (version 2.1.1, dated 07-02-06).
    /// </summary>
    /// <remarks>Tarkin classes are NOT thread-safe.</remarks>
    public abstract class MultiplicityElement : Element
    {

#region Private Members

        /// <summary>
        /// Whether the MultiplicityElement is ordered or not.
        /// </summary>
        private bool isOrdered = false;
        
        /// <summary>
        /// Whether the MultiplicityElement is unique or not.
        /// </summary>
        private bool isUnique = true;
        
        /// <summary>
        /// The lower value of the MultiplicityElement.
        /// </summary>
        private uint lower = 1;
        
        /// <summary>
        /// The upper value of the MultiplicityElement.
        /// </summary>
        private UnlimitedNatural upper = null;

#endregion


#region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        public MultiplicityElement () : base ()
        {
            Upper.Value = "1";
        }

        /// <summary>
        /// Overloaded constructor.
        /// </summary>
        /// <param name="isOrdered">Whether the MultiplicityElement is ordered or not.</param>
        /// <param name="isUnique">Whether the MultiplicityElement is unique or not.</param>
        /// <param name="lower">The lower value of the MultiplicityElement.</param>
        /// <param name="upper">The upper value of the MultiplicityElement.</param>
        public MultiplicityElement ( bool isOrdered,
                                     bool isUnique,
                                     uint lower,
                                     UnlimitedNatural upper ) : base ()
        {
            IsOrdered = isOrdered;
            IsUnique = isUnique;
            Upper = upper;
            Lower = lower;
        }

        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="multiplicityElement">A instance of MultiplicityElment from which to construct a new object.</param>
        public MultiplicityElement ( MultiplicityElement multiplicityElement )
        {
            IsOrdered = multiplicityElement.IsOrdered;
            IsOrdered = multiplicityElement.IsUnique;
            Upper = multiplicityElement.Upper;
            Lower = multiplicityElement.Lower;
        }

#endregion


#region Public Properties

        /// <summary>
        /// Whether the MultiplicityElement is ordered or not.
        /// </summary>
        public bool IsOrdered
        {
            get
            {
                return isOrdered;
            }

            set
            {
                isOrdered = value;
            }
        }

        /// <summary>
        /// Whether the MultiplicityElement is unique or not.
        /// </summary>
        public bool IsUnique
        {
            get
            {
                return isUnique;
            }

            set
            {
                isUnique = value;
            }
        }

        /// <summary>
        /// The lower value of the MultiplicityElement.
        /// 
        /// Lower value must be equal to, or less than, the Upper value.
        /// 
        /// If the lower value exceeds the upper value than an instance of
        /// ArgumentException is thrown.
        /// </summary>
        public uint Lower
        {
            get
            {
                return lower;
            }

            set
            {
                if ( upper.Value != UnlimitedNatural.UnlimitedNaturalInfinity )
                {
                    if ( value > uint.Parse ( upper.Value ) )
                    {
                        throw new ArgumentException ( String.Format ( "Lower value of {0} exceeds the Upper value of {1}", value, Upper.ToString () ) );
                    }
                }

                lower = value;
            }
        }

        /// <summary>
        /// The upper value of the MultiplicityElement.
        /// 
        /// Upper value must be equal to, or greater than, the Lower value.
        /// 
        /// If the upper value is less than the lower value than an instance of
        /// ArgumentException is thrown.
        /// </summary>
        public UnlimitedNatural Upper
        {
            get
            {
                if ( upper == null )
                {
                    upper = new UnlimitedNatural ();
                }

                return upper;
            }

            set
            {
                if ( value == null )
                {
                    throw new ArgumentNullException ( "UnlimitedNatural value cannot be null!" );
                }

                if ( value.Value != UnlimitedNatural.UnlimitedNaturalInfinity )
                {
                    if ( uint.Parse ( value.Value ) < lower )
                    {
                        throw new ArgumentException ( String.Format ( "Upper value of {0} less than the Lower value of {1}", value, Lower.ToString () ) );
                    }
                }

                upper = value;
            }
        }

#endregion

    }
}
